import json
import os
import time
import tkinter as tk
import uuid
from datetime import datetime
from tkinter import ttk, scrolledtext, messagebox, simpledialog

import requests
import ttkbootstrap as ttk
from tinydb import TinyDB, Query
from tinydb.middlewares import CachingMiddleware
from tinydb.storages import JSONStorage
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


@annotate(ClassInfo(name="API", category="tool"))
class ApiView(View):
    """设置视图"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 初始化数据库
        self.init_database()

        # 初始化变量
        self.current_collection_id = None
        self.current_api_id = None
        self.request_methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]

        # 创建UI
        self._create_widgets()

        # 加载数据
        self.load_collections()

    def init_database(self):
        """初始化TinyDB数据库"""
        db_dir = os.path.expanduser("~/.api_test_tool")
        if not os.path.exists(db_dir):
            os.makedirs(db_dir)
        db_path = os.path.join(db_dir, "enhanced_api_data.json")
        self.db = TinyDB(db_path, storage=CachingMiddleware(JSONStorage))
        self.collections_table = self.db.table("collections")  # API集合
        self.apis_table = self.db.table("apis")  # API详情

    def _create_widgets(self):
        """创建界面组件"""
        # 主容器
        main_container = ttk.Frame(self, padding=10)
        main_container.pack(fill=BOTH, expand=YES)

        # 左侧导航面板 - API集合和请求列表
        nav_frame = ttk.LabelFrame(main_container, text="API集合", padding=10)
        nav_frame.pack(side=LEFT, fill=Y, padx=5, ipady=5)

        # 集合操作按钮
        collection_btn_frame = ttk.Frame(nav_frame)
        collection_btn_frame.pack(fill=X, pady=5)

        ttk.Button(
            collection_btn_frame,
            text="新建集合",
            command=self.create_new_collection,
            bootstyle=PRIMARY,
            width=10
        ).pack(side=LEFT, padx=2)

        ttk.Button(
            collection_btn_frame,
            text="重命名",
            command=self.rename_collection,
            bootstyle=SECONDARY,
            width=10
        ).pack(side=LEFT, padx=2)

        ttk.Button(
            collection_btn_frame,
            text="删除",
            command=self.delete_collection,
            bootstyle=DANGER,
            width=10
        ).pack(side=LEFT, padx=2)

        # 集合列表
        self.collections_tree = ttk.Treeview(nav_frame, show="tree", height=8)
        self.collections_tree.pack(fill=X, pady=5)
        self.collections_tree.bind("<<TreeviewSelect>>", self.on_collection_select)

        # API操作按钮
        api_btn_frame = ttk.Frame(nav_frame)
        api_btn_frame.pack(fill=X, pady=5)

        ttk.Button(
            api_btn_frame,
            text="添加API",
            command=self.add_new_api,
            bootstyle=SUCCESS,
            width=10
        ).pack(side=LEFT, padx=2)

        ttk.Button(
            api_btn_frame,
            text="复制API",
            command=self.duplicate_api,
            bootstyle=INFO,
            width=10
        ).pack(side=LEFT, padx=2)

        ttk.Button(
            api_btn_frame,
            text="删除API",
            command=self.delete_api,
            bootstyle=DANGER,
            width=10
        ).pack(side=LEFT, padx=2)

        # API列表
        ttk.Label(nav_frame, text="API请求列表:").pack(anchor=W, pady=2)
        self.apis_tree = ttk.Treeview(nav_frame, show="tree", height=15)
        self.apis_tree.pack(fill=BOTH, expand=YES, pady=5)
        self.apis_tree.bind("<<TreeviewSelect>>", self.on_api_select)

        # 右侧主内容区域
        content_container = ttk.Frame(main_container)
        content_container.pack(side=RIGHT, fill=BOTH, expand=YES)

        # 顶部请求配置区域
        request_config_frame = ttk.LabelFrame(content_container, text="请求配置", padding=10)
        request_config_frame.pack(fill=X, pady=5)

        # API名称
        name_frame = ttk.Frame(request_config_frame)
        name_frame.pack(fill=X, pady=5)

        ttk.Label(name_frame, text="API名称:").pack(side=LEFT, padx=5)
        self.api_name_var = tk.StringVar(value="未命名API")
        name_entry = ttk.Entry(name_frame, textvariable=self.api_name_var)
        name_entry.pack(side=LEFT, padx=5, fill=X, expand=YES)

        # 请求方法和URL
        method_url_frame = ttk.Frame(request_config_frame)
        method_url_frame.pack(fill=X, pady=5)

        # 请求方法选择
        self.method_var = tk.StringVar(value="GET")
        method_combo = ttk.Combobox(
            method_url_frame,
            textvariable=self.method_var,
            values=self.request_methods,
            width=10,
            state="readonly"
        )
        method_combo.pack(side=LEFT, padx=5)

        # URL输入
        ttk.Label(method_url_frame, text="URL:").pack(side=LEFT, padx=5)
        self.url_var = tk.StringVar(value="https://")
        url_entry = ttk.Entry(method_url_frame, textvariable=self.url_var)
        url_entry.pack(side=LEFT, padx=5, fill=X, expand=YES)

        # 操作按钮
        action_btn_frame = ttk.Frame(request_config_frame)
        action_btn_frame.pack(side=RIGHT, padx=5)

        ttk.Button(
            action_btn_frame,
            text="保存",
            command=self.save_current_api,
            bootstyle=INFO,
            width=10
        ).pack(side=LEFT, padx=5)

        ttk.Button(
            action_btn_frame,
            text="发送",
            command=self.send_request,
            bootstyle=SUCCESS,
            width=10
        ).pack(side=LEFT, padx=5)

        # 中间内容区域（分左右两部分）
        middle_frame = ttk.Frame(content_container)
        middle_frame.pack(fill=BOTH, expand=YES, pady=5)

        # 左侧：请求头和请求体
        request_frame = ttk.LabelFrame(middle_frame, text="请求内容", padding=10)
        request_frame.pack(side=LEFT, fill=BOTH, expand=YES, padx=5)

        # 请求头
        headers_frame = ttk.LabelFrame(request_frame, text="请求头 (Key:Value 每行一个)", padding=10)
        headers_frame.pack(fill=BOTH, expand=YES, pady=5)

        self.headers_text = scrolledtext.ScrolledText(headers_frame, wrap=tk.WORD, height=6)
        self.headers_text.pack(fill=BOTH, expand=YES)
        # 默认请求头
        self.headers_text.insert(tk.END, "Content-Type: application/json\n")
        self.headers_text.insert(tk.END, "Accept: application/json\n")

        # 请求体
        body_frame = ttk.LabelFrame(request_frame, text="请求体", padding=10)
        body_frame.pack(fill=BOTH, expand=YES, pady=5)

        self.body_text = scrolledtext.ScrolledText(body_frame, wrap=tk.WORD)
        self.body_text.pack(fill=BOTH, expand=YES)

        # 右侧：响应结果
        response_frame = ttk.LabelFrame(middle_frame, text="响应结果", padding=10)
        response_frame.pack(side=RIGHT, fill=BOTH, expand=YES, padx=5)

        # 响应状态
        response_status_frame = ttk.Frame(response_frame)
        response_status_frame.pack(fill=X, pady=5)

        ttk.Label(response_status_frame, text="状态码:").pack(side=LEFT, padx=5)
        self.status_code_var = tk.StringVar(value="")
        ttk.Label(
            response_status_frame,
            textvariable=self.status_code_var,
            font=("Arial", 10, "bold")
        ).pack(side=LEFT, padx=5)

        ttk.Label(response_status_frame, text="响应时间:").pack(side=LEFT, padx=15)
        self.response_time_var = tk.StringVar(value="")
        ttk.Label(response_status_frame, textvariable=self.response_time_var).pack(side=LEFT, padx=5)

        # 响应内容
        self.response_text = scrolledtext.ScrolledText(response_frame, wrap=tk.WORD)
        self.response_text.pack(fill=BOTH, expand=YES, pady=5)

        # 底部历史记录区域
        history_frame = ttk.LabelFrame(content_container, text="请求历史", padding=10)
        history_frame.pack(fill=BOTH, expand=YES, pady=5)

        # 历史记录表格
        columns = ("timestamp", "method", "url", "status", "time")
        self.history_tree = ttk.Treeview(
            history_frame,
            columns=columns,
            show="headings",
            height=4
        )

        # 设置列标题和宽度
        self.history_tree.heading("timestamp", text="时间")
        self.history_tree.heading("method", text="方法")
        self.history_tree.heading("url", text="URL")
        self.history_tree.heading("status", text="状态")
        self.history_tree.heading("time", text="响应时间")

        self.history_tree.column("timestamp", width=150, anchor=CENTER)
        self.history_tree.column("method", width=80, anchor=CENTER)
        self.history_tree.column("url", width=350, anchor=W)
        self.history_tree.column("status", width=80, anchor=CENTER)
        self.history_tree.column("time", width=100, anchor=CENTER)

        # 添加滚动条
        history_scroll = ttk.Scrollbar(history_frame, orient=VERTICAL, command=self.history_tree.yview)
        self.history_tree.configure(yscroll=history_scroll.set)

        # 布局
        self.history_tree.pack(side=LEFT, fill=BOTH, expand=YES)
        history_scroll.pack(side=RIGHT, fill=Y)

    def load_collections(self):
        """加载所有API集合"""
        # 清空现有集合
        for item in self.collections_tree.get_children():
            self.collections_tree.delete(item)

        # 从数据库获取集合
        collections = self.collections_table.all()

        # 添加到树形视图
        for coll in collections:
            self.collections_tree.insert("", tk.END, id=coll["id"], text=coll["name"])

        # 如果有集合，默认选择第一个
        if collections:
            self.collections_tree.selection_set(collections[0]["id"])
            self.on_collection_select(None)

    def load_apis_in_collection(self, collection_id):
        """加载指定集合中的所有API"""
        # 清空现有API
        for item in self.apis_tree.get_children():
            self.apis_tree.delete(item)

        # 从数据库获取该集合的API
        Api = Query()
        apis = self.apis_table.search(Api.collection_id == collection_id)

        # 按名称排序
        apis.sort(key=lambda x: x["name"])

        # 添加到树形视图
        for api in apis:
            self.apis_tree.insert("", tk.END, id=api["id"], text=api["name"])

    def create_new_collection(self):
        """创建新的API集合"""
        name = simpledialog.askstring("新建集合", "请输入集合名称:")
        if name and name.strip():
            # 生成唯一ID
            coll_id = str(uuid.uuid4())
            # 插入数据库
            self.collections_table.insert({
                "id": coll_id,
                "name": name.strip(),
                "created_at": datetime.now().isoformat()
            })
            # 重新加载集合
            self.load_collections()
            # 选择新创建的集合
            self.collections_tree.selection_set(coll_id)
            self.on_collection_select(None)

    def rename_collection(self):
        """重命名选中的集合"""
        selected = self.collections_tree.selection()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个集合")
            return

        coll_id = selected[0]
        # 获取当前名称
        coll_name = self.collections_tree.item(coll_id, "text")
        # 请求新名称
        new_name = simpledialog.askstring("重命名集合", "请输入新名称:", initialvalue=coll_name)

        if new_name and new_name.strip() and new_name != coll_name:
            # 更新数据库
            Coll = Query()
            self.collections_table.update(
                {"name": new_name.strip()},
                Coll.id == coll_id
            )
            # 更新视图
            self.collections_tree.item(coll_id, text=new_name.strip())

    def delete_collection(self):
        """删除选中的集合及其中的API"""
        selected = self.collections_tree.selection()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个集合")
            return

        coll_id = selected[0]
        coll_name = self.collections_tree.item(coll_id, "text")

        if messagebox.askyesno("确认删除", f"确定要删除集合 '{coll_name}' 及其所有API吗？"):
            # 删除集合
            Coll = Query()
            self.collections_table.remove(Coll.id == coll_id)

            # 删除该集合下的所有API
            Api = Query()
            self.apis_table.remove(Api.collection_id == coll_id)

            # 重新加载
            self.load_collections()
            # 清空API列表
            for item in self.apis_tree.get_children():
                self.apis_tree.delete(item)
            # 重置当前编辑的API
            self.reset_api_form()

    def add_new_api(self):
        """在当前集合中添加新API"""
        if not self.current_collection_id:
            messagebox.showwarning("警告", "请先选择一个集合")
            return

        # 创建新API ID
        api_id = str(uuid.uuid4())
        # 默认名称
        default_name = f"新API {len(self.apis_tree.get_children()) + 1}"

        # 插入数据库
        self.apis_table.insert({
            "id": api_id,
            "collection_id": self.current_collection_id,
            "name": default_name,
            "method": "GET",
            "url": "https://",
            "headers": "Content-Type: application/json\nAccept: application/json\n",
            "body": "",
            "created_at": datetime.now().isoformat(),
            "history": []
        })

        # 重新加载API列表
        self.load_apis_in_collection(self.current_collection_id)
        # 选择新创建的API
        self.apis_tree.selection_set(api_id)
        self.on_api_select(None)

    def duplicate_api(self):
        """复制当前选中的API"""
        selected = self.apis_tree.selection()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个API")
            return

        if not self.current_collection_id:
            return

        original_api_id = selected[0]
        # 获取原始API数据
        Api = Query()
        original_api = self.apis_table.get(Api.id == original_api_id)

        if original_api:
            # 创建新API ID
            new_api_id = str(uuid.uuid4())
            # 新名称
            new_name = f"{original_api['name']} (副本)"

            # 复制数据（不复制历史记录和ID）
            new_api_data = {
                "id": new_api_id,
                "collection_id": self.current_collection_id,
                "name": new_name,
                "method": original_api["method"],
                "url": original_api["url"],
                "headers": original_api["headers"],
                "body": original_api["body"],
                "created_at": datetime.now().isoformat(),
                "history": []
            }

            # 插入数据库
            self.apis_table.insert(new_api_data)

            # 重新加载API列表
            self.load_apis_in_collection(self.current_collection_id)
            # 选择新创建的API
            self.apis_tree.selection_set(new_api_id)
            self.on_api_select(None)

    def delete_api(self):
        """删除选中的API"""
        selected = self.apis_tree.selection()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个API")
            return

        api_id = selected[0]
        api_name = self.apis_tree.item(api_id, "text")

        if messagebox.askyesno("确认删除", f"确定要删除API '{api_name}'吗？"):
            # 删除API
            Api = Query()
            self.apis_table.remove(Api.id == api_id)

            # 重新加载API列表
            self.load_apis_in_collection(self.current_collection_id)

            # 如果删除的是当前编辑的API，重置表单
            if self.current_api_id == api_id:
                self.reset_api_form()

    def on_collection_select(self, event):
        """当选择不同集合时触发"""
        selected = self.collections_tree.selection()
        if selected:
            self.current_collection_id = selected[0]
            # 加载该集合的API
            self.load_apis_in_collection(self.current_collection_id)
            # 重置当前API
            self.current_api_id = None
            self.reset_api_form()

    def on_api_select(self, event):
        """当选择不同API时触发"""
        selected = self.apis_tree.selection()
        if selected:
            self.current_api_id = selected[0]
            # 加载API数据
            self.load_api_data(self.current_api_id)

    def load_api_data(self, api_id):
        """加载API数据到表单"""
        Api = Query()
        api_data = self.apis_table.get(Api.id == api_id)

        if api_data:
            # 填充表单
            self.api_name_var.set(api_data["name"])
            self.method_var.set(api_data["method"])
            self.url_var.set(api_data["url"])
            self.headers_text.delete("1.0", tk.END)
            self.headers_text.insert(tk.END, api_data["headers"])
            self.body_text.delete("1.0", tk.END)
            self.body_text.insert(tk.END, api_data["body"])

            # 加载历史记录
            self.load_api_history(api_data.get("history", []))

    def reset_api_form(self):
        """重置API表单"""
        self.current_api_id = None
        self.api_name_var.set("未命名API")
        self.method_var.set("GET")
        self.url_var.set("https://")
        self.headers_text.delete("1.0", tk.END)
        self.headers_text.insert(tk.END, "Content-Type: application/json\nAccept: application/json\n")
        self.body_text.delete("1.0", tk.END)
        self.status_code_var.set("")
        self.response_time_var.set("")
        self.response_text.delete("1.0", tk.END)

        # 清空历史记录
        for item in self.history_tree.get_children():
            self.history_tree.delete(item)

    def save_current_api(self):
        """保存当前编辑的API"""
        if not self.current_collection_id:
            messagebox.showwarning("警告", "请先选择一个集合")
            return

        api_name = self.api_name_var.get().strip()
        if not api_name:
            messagebox.showwarning("警告", "请输入API名称")
            return

        url = self.url_var.get().strip()
        if not url:
            messagebox.showwarning("警告", "请输入URL")
            return

        # 收集表单数据
        api_data = {
            "name": api_name,
            "method": self.method_var.get(),
            "url": url,
            "headers": self.headers_text.get("1.0", tk.END).strip(),
            "body": self.body_text.get("1.0", tk.END).strip()
        }

        if self.current_api_id:
            # 更新现有API
            Api = Query()
            self.apis_table.update(api_data, Api.id == self.current_api_id)
            # 更新树形视图中的名称
            self.apis_tree.item(self.current_api_id, text=api_name)
            messagebox.showinfo("成功", "API已更新")
        else:
            # 创建新API
            self.add_new_api()
            # 重新获取当前API ID（最后一个）
            Api = Query()
            apis = self.apis_table.search(Api.collection_id == self.current_collection_id)
            if apis:
                latest_api = max(apis, key=lambda x: x["created_at"])
                self.current_api_id = latest_api["id"]
                # 再次保存以更新数据
                self.apis_table.update(api_data, Api.id == self.current_api_id)
                # 更新树形视图中的名称
                self.apis_tree.item(self.current_api_id, text=api_name)
                messagebox.showinfo("成功", "新API已创建")

    def parse_headers(self):
        """解析请求头文本为字典"""
        headers = {}
        headers_text = self.headers_text.get("1.0", tk.END).strip()

        for line in headers_text.split("\n"):
            line = line.strip()
            if ":" in line:
                key, value = line.split(":", 1)
                headers[key.strip()] = value.strip()

        return headers

    def parse_body(self):
        """解析请求体文本"""
        body_text = self.body_text.get("1.0", tk.END).strip()
        if not body_text:
            return None

        # 尝试解析为JSON
        try:
            return json.loads(body_text)
        except json.JSONDecodeError:
            # 如果不是JSON，直接返回文本
            return body_text

    def send_request(self):
        """发送API请求"""
        if not self.current_api_id:
            # 先保存为新API
            save_confirm = messagebox.askyesno("提示", "当前API未保存，是否保存并发送？")
            if not save_confirm:
                return
            self.save_current_api()
            if not self.current_api_id:
                return

        method = self.method_var.get()
        url = self.url_var.get().strip()

        if not url:
            messagebox.showerror("错误", "请输入URL")
            return

        # 解析请求头和请求体
        headers = self.parse_headers()
        body = self.parse_body()

        # 清空之前的响应
        self.status_code_var.set("")
        self.response_time_var.set("")
        self.response_text.delete("1.0", tk.END)

        try:
            # 记录开始时间
            start_time = time.time()

            # 根据请求方法发送请求
            if method == "GET":
                response = requests.get(url, headers=headers, timeout=10)
            elif method == "POST":
                response = requests.post(url, headers=headers, json=body, timeout=10)
            elif method == "PUT":
                response = requests.put(url, headers=headers, json=body, timeout=10)
            elif method == "DELETE":
                response = requests.delete(url, headers=headers, timeout=10)
            elif method == "PATCH":
                response = requests.patch(url, headers=headers, json=body, timeout=10)
            elif method == "HEAD":
                response = requests.head(url, headers=headers, timeout=10)
            elif method == "OPTIONS":
                response = requests.options(url, headers=headers, timeout=10)
            else:
                messagebox.showerror("错误", f"不支持的请求方法: {method}")
                return

            # 计算响应时间
            response_time = (time.time() - start_time) * 1000  # 转换为毫秒

            # 更新状态信息
            status_code = response.status_code
            self.status_code_var.set(str(status_code))
            self.response_time_var.set(f"{response_time:.2f} ms")

            # 显示响应内容
            response_content = ""
            try:
                # 尝试以JSON格式显示
                response_json = response.json()
                response_content = json.dumps(response_json, indent=2, ensure_ascii=False)
                self.response_text.insert(tk.END, response_content)
            except:
                # 否则显示文本
                response_content = response.text
                self.response_text.insert(tk.END, response_content)

            # 保存请求历史
            self.save_request_history(status_code, response_time, response_content)

        except Exception as e:
            # 显示错误信息
            error_msg = f"请求错误: {str(e)}"
            self.response_text.insert(tk.END, error_msg)
            self.status_code_var.set("错误")
            messagebox.showerror("请求失败", error_msg)

            # 保存错误历史
            self.save_request_history("错误", 0, error_msg)

    def save_request_history(self, status_code, response_time, response_content):
        """保存请求历史记录"""
        if not self.current_api_id:
            return

        # 获取当前API
        Api = Query()
        api_data = self.apis_table.get(Api.id == self.current_api_id)

        if api_data:
            # 创建历史记录
            history_entry = {
                "timestamp": datetime.now().isoformat(),
                "method": self.method_var.get(),
                "url": self.url_var.get().strip(),
                "status_code": status_code,
                "response_time": response_time,
                "response_content": response_content
            }

            # 获取现有历史并添加新记录
            history = api_data.get("history", [])
            # 限制历史记录数量为20条
            if len(history) >= 20:
                history = history[1:]  # 移除最旧的记录
            history.append(history_entry)

            # 更新数据库
            self.apis_table.update({"history": history}, Api.id == self.current_api_id)

            # 更新历史记录显示
            self.load_api_history(history)

    def load_api_history(self, history):
        """加载API的请求历史"""
        # 清空现有历史
        for item in self.history_tree.get_children():
            self.history_tree.delete(item)

        # 按时间倒序显示
        for entry in reversed(history):
            timestamp = datetime.fromisoformat(entry["timestamp"]).strftime("%Y-%m-%d %H:%M:%S")
            status = entry["status_code"]
            # 根据状态码设置颜色标签
            tag = "success" if str(status).startswith("2") else "error" if status == "错误" else "warning"
            self.history_tree.insert(
                "",
                tk.END,
                values=(
                    timestamp,
                    entry["method"],
                    entry["url"],
                    status,
                    f"{entry['response_time']:.2f} ms" if entry["response_time"] else ""
                ),
                tags=(tag,)
            )

        # 配置标签样式
        self.history_tree.tag_configure("success", foreground="green")
        self.history_tree.tag_configure("error", foreground="red")
        self.history_tree.tag_configure("warning", foreground="#ffaa00")

    def create_widgets(self):
        pass
